package com.fudan.es.aggs;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket;
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
import org.elasticsearch.search.aggregations.bucket.nested.Nested;
import org.elasticsearch.search.aggregations.bucket.nested.ReverseNested;
import org.springframework.stereotype.Component;

import com.fudan.es.aggs.handler.base.AggsHandler;
import com.fudan.es.aggs.response.handler.ResponseHandler;
import com.fudan.es.entity.DimensionPack;
import com.fudan.es.entity.FieldMeta;
import com.fudan.es.entity.MetricPack;

@Component
public class ResponseParser {

	private static final String ROOT_PATH = ConstString.ROOT_PATH;
	private static final String DEFAULT_DOC = ConstString.DEFAULT_DOC;
	private static final String ALL_FILTER = ConstString.ALL_FILTER;
	public Map<String,Object> extractResponse(DimensionPack dimensionPack,SearchResponse response) {
		Map<String,Object> map = new HashMap<String,Object>();
		Integer fieldId = dimensionPack.getField().getId();
		if(fieldId == null) {
			Filter filterAggsResp = response.getAggregations().get(ALL_FILTER);
			Aggregations aggregations = filterAggsResp.getAggregations();

			extract(map,aggregations,dimensionPack.getMetric(),ROOT_PATH);
			//handle aggregation>subaggregation
		}
		if(fieldId != null) {
			map.put(fieldId.toString(), new HashMap<String,Object>());
			FieldMeta dimensionField = dimensionPack.getField();
			MultiBucketsAggregation multiBuckets = null;
			if(dimensionField.getInNested()) {
				Nested nested = response.getAggregations().get(dimensionField.getNestedPath());
				multiBuckets = nested.getAggregations().get(dimensionPack.getType().toString()+"$"+fieldId);
			}else {
				multiBuckets = response.getAggregations().get(dimensionPack.getType().toString()+"$"+fieldId);
			}
			List<? extends Bucket> buckets = multiBuckets.getBuckets();
			for (Bucket bucket : buckets) {
			Map<String,Object> target = (Map<String, Object>) map.get(fieldId.toString());
			Map<String,Object> atom = new HashMap<>();
			//atom.put(DEFAULT_DOC, bucket.getDocCount());
			if(dimensionPack.getField().getInNested()) {
				ReverseNested reverse = bucket.getAggregations().get("root");
				atom.put(DEFAULT_DOC, reverse.getDocCount());				
			}else {
				atom.put(DEFAULT_DOC, bucket.getDocCount());
			}
			target.put(bucket.getKeyAsString(), atom);
				//
			extract(atom,bucket.getAggregations(),dimensionPack.getMetric(),dimensionPack.getField().getNestedPath());
			}
		}
		return map;
	}

	//???
	public void extract(Map<String,Object> map,Aggregations aggregations,List<MetricPack> metricPacks,String path) {
		if(map == null || metricPacks == null) return;
		for (MetricPack metricPack : metricPacks) {
			FieldMeta field = metricPack.getField();
			if(field.getInNested()) {
				if(path == null || path.equals(ROOT_PATH)) {
					//field:nested,now_path:root
					Nested nested = aggregations.get(field.getNestedPath());
					AggsHandler.buildHandler(metricPack.getType()).handle(map, nested.getAggregations(), metricPack);
					//ResponseHandler.buildHandler(metricPack.getType()).handle(map, nested.getAggregations(), metricPack);
				}else {
					//field:nested,now_path:nested
					if(field.getNestedPath().equals(path)) {
						//ResponseHandler.buildHandler(metricPack.getType()).handle(map, aggregations, metricPack);
						AggsHandler.buildHandler(metricPack.getType()).handle(map, aggregations, metricPack);
					}else if(field.getNestedPath().contains(path)) {
						Nested nested = aggregations.get(field.getNestedPath());
						AggsHandler.buildHandler(metricPack.getType()).handle(map, nested.getAggregations(), metricPack);
						//ResponseHandler.buildHandler(metricPack.getType()).handle(map, nested.getAggregations(), metricPack);
					}else if(path.contains(field.getNestedPath())) {
						ReverseNested reverseNested = aggregations.get(field.getNestedPath());
						AggsHandler.buildHandler(metricPack.getType()).handle(map, reverseNested.getAggregations(), metricPack);
						//ResponseHandler.buildHandler(metricPack.getType()).handle(map, reverseNested.getAggregations(), metricPack);
					}else {
						ReverseNested reverseNested = aggregations.get(ROOT_PATH);
						Nested nested = reverseNested.getAggregations().get(field.getNestedPath());
						AggsHandler.buildHandler(metricPack.getType()).handle(map, nested.getAggregations(), metricPack);
						//ResponseHandler.buildHandler(metricPack.getType()).handle(map, nested.getAggregations(), metricPack);
					}
				}
			}else {
				if(path == null || path.equals(ROOT_PATH)) {
					//field:root,now_path:root
					AggsHandler.buildHandler(metricPack.getType()).handle(map, aggregations, metricPack);
					//ResponseHandler.buildHandler(metricPack.getType()).handle(map, aggregations, metricPack);
				}else {
					//field:root,now_path:nested
					ReverseNested reverseNested = aggregations.get(ROOT_PATH);
					AggsHandler.buildHandler(metricPack.getType()).handle(map, reverseNested.getAggregations(), metricPack);
					//ResponseHandler.buildHandler(metricPack.getType()).handle(map, reverseNested.getAggregations(), metricPack);
				}
			}
		}
	}
}
